package music;

import java.io.File;
import java.io.IOException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

public class OggFile extends Thread {
	AudioInputStream in;
	AudioInputStream din;

	AudioFormat baseFormat;
	AudioFormat decodedFormat;
	SourceDataLine line;
	OggFileStatus status = OggFileStatus.Pause;
	FloatControl control;
	OggFile syncAudio;
	long time = 0;

	public OggFile(File file) {
		open(file);
	}

	public FloatControl getControl() {
		return control;
	}

	public void open(File file) {
		try {
			in = AudioSystem.getAudioInputStream(file);
		} catch (UnsupportedAudioFileException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		baseFormat = in.getFormat();
		decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
				baseFormat.getSampleRate(), 16, baseFormat.getChannels(),
				baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false);
		// Get AudioInputStream that will be decoded by underlying VorbisSPI
		din = AudioSystem.getAudioInputStream(decodedFormat, in);
	}

	public synchronized void waitCommand() {
		// TODO Auto-generated constructor stub
		while (true) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			switch (status) {
			case Play:
				try {
					rawplay(decodedFormat, din);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (LineUnavailableException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				play();
				break;
			case Kill:
				return;
			}
		}
	}

	public void run() {
		waitCommand();
	}

	public synchronized void play() {
		status = OggFileStatus.Play;
		notify();

	}

	public long getTime() {
		long time = 0;
		if (line != null)
			time = line.getMicrosecondPosition() / 1000;
		return time;
	}

	private void rawplay(AudioFormat targetFormat, AudioInputStream din)
			throws IOException, LineUnavailableException {
		byte[] data = new byte[4096];
		line = getLine(targetFormat);
		control = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN);
		if (line != null) {
			// Start
			line.start();
			int nBytesRead = 0, nBytesWritten = 0;
			while (nBytesRead != -1) {
				nBytesRead = din.read(data, 0, data.length);
				if (nBytesRead != -1)
					nBytesWritten = line.write(data, 0, nBytesRead);
				// time = line.getMicrosecondPosition() / 1000;
				if (status == OggFileStatus.Kill)
					break;
				if (syncAudio != null)
					System.out.println(getTime() - syncAudio.getTime());
			}
			// Stop
			line.drain();
			line.stop();
			line.close();
			din.close();
		}
	}

	private SourceDataLine getLine(AudioFormat audioFormat)
			throws LineUnavailableException {
		SourceDataLine res = null;
		DataLine.Info info = new DataLine.Info(SourceDataLine.class,
				audioFormat);
		res = (SourceDataLine) AudioSystem.getLine(info);
		res.open(audioFormat);
		return res;
	}

	public void play(OggFile syncAudio) {
		// TOD,O Auto-generated method stub
		play();
		this.syncAudio = syncAudio;
	}

}
